package cn.iocoder.an.module.business.utils;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Builder;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.context.event.EventListener;
import org.springframework.http.*;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

/**
 * 企业微信消息推送工具类
 * 基于企业微信应用消息API (https://work.weixin.qq.com/api/doc/90000/90135/90236)
 */
@Component
@Slf4j
public class WeComMessageUtil {

    // 从 application.yml 或 application.properties 中读取配置
    @Value("${wecom.corp.id}")
    private String corpId;

    @Value("${wecom.corp.secret}")
    private String corpSecret;

    @Value("${wecom.agent.id}")
    private Integer agentId;

    // 用于获取 access_token 的 URL
    private static final String GET_TOKEN_URL = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=%s&corpsecret=%s";
    // 发送应用消息的 URL
    private static final String SEND_MESSAGE_URL = "https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=%s";

    // 存储获取到的 access_token
    private String accessToken;
    // access_token 的过期时间戳 (毫秒)
    private long tokenExpiresAt = 0;

    private final RestTemplate restTemplate;
    private final ObjectMapper objectMapper;

    public WeComMessageUtil(RestTemplate restTemplate, ObjectMapper objectMapper) {
        this.restTemplate = restTemplate;
        this.objectMapper = objectMapper;
    }

    /**
     * 在 Bean 初始化后立即刷新一次 access_token (可选)
     */
    @EventListener(ContextRefreshedEvent.class)
    public void init() {
        try {
            refreshToken();
            log.info("企业微信工具类初始化完成，AgentId: {}", agentId);
        } catch (Exception e) {
            log.error("初始化企业微信 access_token 失败", e);
        }
    }

    /**
     * 刷新 access_token
     * 企业微信 access_token 有效期为 2 小时，建议缓存并定时刷新
     */
    private synchronized void refreshToken() throws RuntimeException {
        String url = String.format(GET_TOKEN_URL, corpId, corpSecret);
        try {
            ResponseEntity<WeComTokenResponse> response = restTemplate.getForEntity(url, WeComTokenResponse.class);
            if (response.getStatusCode() == HttpStatus.OK && response.getBody() != null) {
                WeComTokenResponse tokenResponse = response.getBody();
                if (tokenResponse.getErrcode() == 0) {
                    this.accessToken = tokenResponse.getAccess_token();
                    // 提前 5 分钟过期，避免刚好过期
                    this.tokenExpiresAt = System.currentTimeMillis() + (tokenResponse.getExpires_in() - 300) * 1000L;
                    log.debug("刷新 access_token 成功: {}", accessToken);
                } else {
                    throw new RuntimeException("获取 access_token 失败，错误码: " + tokenResponse.getErrcode() +
                            ", 错误信息: " + tokenResponse.getErrmsg());
                }
            } else {
                throw new RuntimeException("HTTP 请求失败，状态码: " + response.getStatusCode());
            }
        } catch (Exception e) {
            log.error("调用企业微信获取 token 接口异常", e);
            throw new RuntimeException("刷新 access_token 失败: " + e.getMessage(), e);
        }
    }

    /**
     * 确保 access_token 有效，如果即将过期则刷新
     */
    private void ensureValidToken() {
        // 如果 token 不存在或即将在 10 分钟内过期，则刷新
        if (accessToken == null || System.currentTimeMillis() >= tokenExpiresAt - 600_000) {
            refreshToken();
        }
    }

    /**
     * 发送文本消息
     * @param content 消息内容
     * @param toUser 接收消息的用户ID列表，多个用 '|' 分隔。特殊: "@" 表示应用可见范围内的所有用户
     * @param toParty 接收消息的部门ID列表，多个用 '|' 分隔
     * @param toTag 接收消息的标签ID列表，多个用 '|' 分隔
     * @return 发送结果
     */
    public WeComSendResult sendTextMessage(String content, String toUser, String toParty, String toTag) {
        Map<String, Object> message = buildBaseMessage("text", toUser, toParty, toTag);
        Map<String, String> text = new HashMap<>();
        text.put("content", content);
        message.put("text", text);
        return sendMessage(message);
    }

    /**
     * 发送文本消息 (简化版，只发给指定用户)
     * @param content 消息内容
     * @param userId 接收用户ID
     * @return 发送结果
     */
    public WeComSendResult sendTextMessageToUser(String content, String userId) {
        return sendTextMessage(content, userId, null, null);
    }

    /**
     * 发送图文消息 (单个图文)
     * @param title 标题
     * @param description 描述
     * @param url 点击后跳转的链接
     * @param picUrl 图文消息的图片链接 (可选)
     * @param toUser 接收消息的用户ID列表
     * @param toParty 接收消息的部门ID列表
     * @param toTag 接收消息的标签ID列表
     * @return 发送结果
     */
    public WeComSendResult sendNewsMessage(String title, String description, String url, String picUrl,
                                           String toUser, String toParty, String toTag) {
        Map<String, Object> message = buildBaseMessage("news", toUser, toParty, toTag);
        Map<String, Object> news = new HashMap<>();
        Map<String, Object> article = new HashMap<>();
        article.put("title", title);
        article.put("description", description);
        article.put("url", url);
        if (picUrl != null && !picUrl.isEmpty()) {
            article.put("picurl", picUrl);
        }
        news.put("articles", Arrays.asList(article));
        message.put("news", news);
        return sendMessage(message);
    }

    /**
     * 发送图文消息 (简化版，只发给指定用户)
     * @param title 标题
     * @param description 描述
     * @param url 点击后跳转的链接
     * @param picUrl 图片链接 (可选)
     * @param userId 接收用户ID
     * @return 发送结果
     */
    public WeComSendResult sendNewsMessageToUser(String title, String description, String url, String picUrl, String userId) {
        return sendNewsMessage(title, description, url, picUrl, userId, null, null);
    }

    /**
     * 构建消息的基础结构
     */
    private Map<String, Object> buildBaseMessage(String msgType, String toUser, String toParty, String toTag) {
        Map<String, Object> message = new HashMap<>();
        message.put("touser", toUser != null ? toUser : "@all"); // 默认发给所有人（应用可见范围内）
        message.put("toparty", toParty);
        message.put("totag", toTag);
        message.put("msgtype", msgType);
        message.put("agentid", agentId);
        // 用于测试，正式环境可移除
        message.put("safe", 0); // 0: 否 1:是，是否加密
        message.put("enable_id_trans", 0); // 0:否 1:是，是否开启id转译
        message.put("enable_duplicate_check", 0); // 0:否 1:是，是否重复消息检查
        return message;
    }

    /**
     * 执行发送消息的 HTTP 请求
     * @param message 消息体 (Map 结构)
     * @return 发送结果
     */
    private WeComSendResult sendMessage(Map<String, Object> message) {
        ensureValidToken(); // 确保 token 有效
        String url = String.format(SEND_MESSAGE_URL, accessToken);
        try {
            // 将 Map 转换为 JSON 字符串
            String jsonBody = objectMapper.writeValueAsString(message);
            log.debug("发送企业微信消息请求: {}", jsonBody);

            // 创建请求实体
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_JSON);
            HttpEntity<String> requestEntity = new HttpEntity<>(jsonBody, headers);

            // 发送 POST 请求
            ResponseEntity<String> response = restTemplate.postForEntity(url, requestEntity, String.class);

            if (response.getStatusCode() == HttpStatus.OK && response.getBody() != null) {
                // 解析响应
                WeComSendResult result = objectMapper.readValue(response.getBody(), WeComSendResult.class);
                if (result.getErrcode() == 0) {
                    log.info("企业微信消息发送成功: {}", result.getErrmsg());
                } else {
                    log.warn("企业微信消息发送失败，错误码: {}, 错误信息: {}", result.getErrcode(), result.getErrmsg());
                }
                return result;
            } else {
                log.error("发送消息 HTTP 请求失败，状态码: {}, 响应体: {}", response.getStatusCode(), response.getBody());
                return WeComSendResult.builder().errcode(-1).errmsg("HTTP 请求失败: " + response.getStatusCode()).build();
            }
        } catch (JsonProcessingException e) {
            log.error("消息体序列化为 JSON 失败", e);
            return WeComSendResult.builder().errcode(-2).errmsg("JSON 序列化失败: " + e.getMessage()).build();
        } catch (Exception e) {
            log.error("发送企业微信消息异常", e);
            return WeComSendResult.builder().errcode(-3).errmsg("发送异常: " + e.getMessage()).build();
        }
    }

    /**
     * 根据手机号查找用户ID (修正版 - 使用 getuserid 接口)
     * @param mobile 手机号码
     * @return 用户ID (如果找到)，否则返回null
     */
    public String getUserIdByMobile(String mobile) {
        ensureValidToken(); // 确保 access_token 有效

        // ✅ 修正：使用正确的 getuserid 接口
        String url = String.format("https://qyapi.weixin.qq.com/cgi-bin/user/getuserid?access_token=%s", accessToken);

        Map<String, String> requestBody = new HashMap<>();
        requestBody.put("mobile", mobile); // 传递手机号

        try {
            String jsonBody = objectMapper.writeValueAsString(requestBody);
            log.debug("发送根据手机号查找用户ID请求: {}", jsonBody);

            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_JSON);
            HttpEntity<String> requestEntity = new HttpEntity<>(jsonBody, headers);

            // 发送 POST 请求
            ResponseEntity<Map> response = restTemplate.postForEntity(url, requestEntity, Map.class);

            if (response.getStatusCode() == HttpStatus.OK && response.getBody() != null) {
                Map<String, Object> responseBody = response.getBody();
                Integer errcode = (Integer) responseBody.get("errcode");

                if (errcode == 0) {
                    // ✅ 修正：正确解析返回的 userid 字段
                    return (String) responseBody.get("userid");
                } else {
                    // ❌ 修正：这里的日志信息也应更新，因为不再是 code 问题
                    log.warn("根据手机号 {} 查找用户失败，错误码: {}, 错误信息: {}",
                            mobile, responseBody.get("errcode"), responseBody.get("errmsg"));
                    return null;
                }
            } else {
                log.error("根据手机号 {} 查找用户 HTTP 请求失败，状态码: {}, 响应体: {}",
                        mobile, response.getStatusCode(), response.getBody());
                return null;
            }
        } catch (JsonProcessingException e) {
            log.error("消息体序列化为 JSON 失败", e);
            throw new RuntimeException("JSON 序列化失败: " + e.getMessage(), e);
        } catch (Exception e) {
            log.error("根据手机号 {} 查找用户异常", mobile, e);
            throw new RuntimeException("根据手机号查找用户失败: " + e.getMessage(), e);
        }
    }

    // --- 响应 DTO (Data Transfer Object) ---
    @Data
    public static class WeComTokenResponse {
        private int errcode;
        private String errmsg;
        private String access_token;
        private int expires_in;
    }

    @Data
    @Builder
    public static class WeComSendResult {
        private int errcode;
        private String errmsg;
        private String invaliduser;
        private String invalidparty;
        private String invalidtag;
        private String unlicensed;
        private String msgid;
        private String response_code;
    }
}